package com.xunlai.infra.permission.manager.web.service.impl;

import com.xunlai.infra.permission.common.exception.DataNotExistException;
import com.xunlai.infra.permission.common.exception.FieldRepeatException;
import com.xunlai.infra.permission.common.exception.PermissionBusinessException;
import com.xunlai.infra.permission.manager.web.converter.RoleConverter;
import com.xunlai.infra.permission.manager.web.service.RoleService;
import com.xunlai.infra.permission.manager.web.vo.*;
import com.xunlai.infra.permission.manager.web.vo.role.*;
import com.xunlai.infra.permission.storage.entity.Role;
import com.xunlai.infra.permission.storage.entity.RolePermission;
import com.xunlai.infra.permission.storage.entity.RoleRelation;
import com.xunlai.infra.permission.storage.repository.RoleRepository;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author liang
 * @date 12/11/22 6:48 PM
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class RoleServiceImpl implements RoleService {

    private RoleRepository roleRepository;

    @Override
    public Long createRole(CreateRoleReqVo createRoleReqVo) throws PermissionBusinessException {
        Optional<Role> existed = roleRepository.findByRoleNameOrRoleCode(createRoleReqVo.getRoleName(), createRoleReqVo.getRoleCode());
        if (existed.isPresent()) {
            if (existed.get().getRoleName().equals(createRoleReqVo.getRoleName())) {
                throw new FieldRepeatException("角色名重复");
            } else {
                throw new FieldRepeatException("角色编码重复");
            }
        }
        Role role = RoleConverter.INSTANCE.convertCreateReq2Role(createRoleReqVo);
        if (role.getEnable() == null) {
            role.setEnable((short) 1);
        }
        role.setDeleted((short)0);
        Role save = roleRepository.save(role);
        return save.getId();
    }

    @Override
    public void createRelation(Long roleId, List<CreateRoleRelationVo> createRoleReqVoList) throws PermissionBusinessException {
        if (CollectionUtils.isEmpty(createRoleReqVoList)) {
            return;
        }
        Optional<Role> roleOptional = roleRepository.findById(roleId);
        if (roleOptional.isEmpty()) {
            throw new DataNotExistException("角色不存在");
        }
        Role role = roleOptional.get();
        List<RoleRelation> roleRelations = createRoleReqVoList.stream()
                .map(RoleConverter.INSTANCE::convertCreateReq2RoleRelation)
                .peek(r -> {
                    r.setRoleId(role.getId());
                    r.setRoleCode(r.getRoleCode());
                }).collect(Collectors.toList());
        role.setRoleRelations(roleRelations);
        roleRepository.save(role);
    }

    @Override
    public void createPermission(Long roleId, List<CreateRolePermissionReqVo> createRolePermissionReqVos) throws PermissionBusinessException {
        if (CollectionUtils.isEmpty(createRolePermissionReqVos)) {
            return;
        }
        Optional<Role> roleOptional = roleRepository.findById(roleId);
        if (roleOptional.isEmpty()) {
            throw new DataNotExistException("角色不存在");
        }
        Role role = roleOptional.get();
        List<RolePermission> rolePermissions = createRolePermissionReqVos.stream()
                .map(RoleConverter.INSTANCE::convertCreateReq2RolePermission)
                .peek(r -> {
                    r.setRoleId(role.getId());
                    r.setRoleCode(r.getRoleCode());
                }).collect(Collectors.toList());
        role.setRolePermissions(rolePermissions);
        roleRepository.save(role);
    }

    @Override
    public void switchEnable(Long roleId, Short enable) throws PermissionBusinessException {
        Optional<Role> roleOptional = roleRepository.findById(roleId);
        if (roleOptional.isEmpty()) {
            throw new DataNotExistException("角色不存在");
        }
        Role role = roleOptional.get();
        role.setEnable(enable);
        roleRepository.save(role);
    }

    @Override
    public void changeRoleName(Long roleId, String roleName) throws PermissionBusinessException {
        Optional<Role> roleOptional = roleRepository.findById(roleId);
        if (roleOptional.isEmpty()) {
            throw new DataNotExistException("角色不存在");
        }
        Role role = roleOptional.get();
        role.setRoleName(roleName);
        roleRepository.save(role);
    }

    @Override
    public boolean deleteRole(Long roleId) throws PermissionBusinessException {
        Optional<Role> roleOptional = roleRepository.findById(roleId);
        if (roleOptional.isEmpty()) {
            return true;
        }
        roleRepository.delete(roleOptional.get());
        return true;
    }

    @Override
    public BasePageRespVo<RoleListVo> pageListRole(QueryRoleReqVo queryRoleReqVo, Integer pageNum, Integer pageSize) {
        Role role = RoleConverter.INSTANCE.convertQueryReq2Role(queryRoleReqVo);
        pageNum = (pageNum == null || pageNum < 1) ? 1 : pageNum;
        int size = (pageSize == null || pageSize <= 0) ? 10 : pageSize;
        Page<Role> rolePage = roleRepository.findAll(
                Example.of(role,
                        ExampleMatcher.matching()
                                .withIgnoreNullValues()
                                .withMatcher("roleName",(g) -> g.caseSensitive().contains())
                                .withMatcher("roleCode",g -> g.caseSensitive().exact())
                )
                , PageRequest.of(pageNum -1, size)
        );
        List<RoleListVo> roleListVos = rolePage.getContent().stream().map(RoleConverter.INSTANCE::convert2RoleListVo).toList();
        return new BasePageRespVo<>(roleListVos,pageNum,size,rolePage.getTotalElements(), rolePage.getTotalPages());
    }

    @Autowired
    public void setRoleRepository(RoleRepository roleRepository) {
        this.roleRepository = roleRepository;
    }
}
